package utils

import (
	"context"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"math/rand"
	"reflect"
	"strings"
	"sync"
	"time"

	"github.com/pkg/errors"
	"sigs.k8s.io/controller-runtime/pkg/client"
)

// SliceRemoveString removes the first occurrence of the given string from the slice.
func SliceRemoveString(slice []string, s string) (result []string) {
	for _, item := range slice {
		if item == s {
			continue
		}
		result = append(result, item)
	}
	return
}

// SliceExcludeSlice removes all the elements of the given exclude slice from the src slice.
func SliceExcludeSlice(src []string, exclude []string) (result []string) {
	for _, item := range exclude {
		if ContainsString(src, item) {
			src = SliceRemoveString(src, item)
		}
	}
	result = src
	return
}

// ContainsString returns true if the given string is in the slice.
func ContainsString(slice []string, s string) bool {
	if slice == nil {
		return false
	}
	for _, item := range slice {
		if strings.Replace(item, "\n", "", -1) == s {
			return true
		}
	}
	return false
}

// SliceContainsSlice returns true if the given dst slice is in the src slice.
func SliceContainsSlice(src []string, dst []string) bool {
	if src == nil {
		return false
	}
	for _, item := range dst {
		if !ContainsString(src, item) {
			return false
		}
	}
	return true
}

// TrimSpaceSlice returns a new slice with all the string in the given slice trimmed.
func TrimSpaceSlice(slice []string) (result []string) {
	for _, item := range slice {
		if item == "" || item == "\n" || item == "\r\n" || item == "\t" || item == " " {
			continue
		}
		result = append(result, strings.TrimSpace(item))
	}
	return
}

func DeepCopy(src interface{}) interface{} {
	data, _ := json.Marshal(src)
	var dst interface{}
	if err := json.Unmarshal(data, dst); err != nil {
		return nil
	}
	return dst
}

// GroupRun 用来按照指定协程数量，运行某一函数,并对错误统一处理
// thread    并发数量
// fn        工作函数，入参为interface{}，需自行在fn函数内对入参类型进行转换
// errFn     错误处理函数,入参为map[interface{}]error， 代表函数fn运行某一variable时,出现的错误
// variables 传入fn函数的参数
func GroupRun(thread int, errFn func(map[interface{}]error), fn func(interface{}) error, variables interface{}) (err error) {
	defer func() {
		if e := recover(); e != nil {
			err = errors.Errorf("%v", e)
		}
	}()
	var wg sync.WaitGroup
	var mu sync.Mutex
	failedMap := make(map[interface{}]error)

	var vs []interface{}
	if reflect.TypeOf(variables).Kind() == reflect.Slice {
		valueOf := reflect.ValueOf(variables)
		for i := 0; i < valueOf.Len(); i++ {
			vs = append(vs, valueOf.Index(i).Interface())
		}
	}

	min := func(a, b int) int {
		if a < b {
			return a
		}
		return b
	}
	for i := 0; i < len(vs); i += thread {
		func(vs []interface{}) {
			for _, v := range vs {
				wg.Add(1)
				go func(v interface{}) {
					defer wg.Done()
					if err := fn(v); err != nil {
						mu.Lock()
						failedMap[v] = err
						mu.Unlock()
					}
				}(v)
			}
			wg.Wait()
		}(vs[i:min(i+thread, len(vs))])
	}
	errFn(failedMap)
	return
}

func ClientObjNS(obj client.Object) string {
	if obj == nil {
		return "object is nil"
	}
	// 检查接口的具体值是否为nil指针
	v := reflect.ValueOf(obj)
	if v.Kind() == reflect.Ptr && v.IsNil() {
		return "obj is nil by reflect"
	}
	return fmt.Sprintf("%s/%s", obj.GetNamespace(), obj.GetName())
}

func CtxDone(ctx context.Context) bool {
	select {
	case <-ctx.Done():
		return true
	default:
		return false
	}
}

// RemoveTimestamps 移除字符串中的时间戳，直接移除后十位字符
func RemoveTimestamps(s string) string {
	return s[:strings.LastIndex(s, "-")]
}

// CommonPrefix Returns the longest common prefix with the most occurrences in a set of strings
func CommonPrefix(strs []string) string {
	if len(strs) == 0 {
		return ""
	}

	counter := make(map[string]int)

	prefix := strs[0]
	for i := 1; i < len(strs); i++ {
		prefix = CommonPrefixOfTwo(prefix, strs[i])
		if prefix == "" {
			continue
		}
		counter[prefix]++
	}

	max := 0
	for k, v := range counter {
		if v > max {
			max = v
			prefix = k
		}
	}
	return prefix
}

func CommonPrefixOfTwo(str1, str2 string) string {
	length := min(len(str1), len(str2))
	index := 0
	for index < length && str1[index] == str2[index] {
		index++
	}
	return str1[:index]
}

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func RemoveDuplicateElement(s []string) []string {
	result := []string{}
	temp := map[string]struct{}{}
	for _, item := range s {
		if _, ok := temp[item]; !ok {
			temp[item] = struct{}{}
			result = append(result, item)
		}
	}
	return result
}

// B64Encode base64 encode
func B64Encode(s string) string {
	return base64.StdEncoding.EncodeToString([]byte(s))
}

// B64Decode base64 decode
func B64Decode(s string) (string, error) {
	b, err := base64.StdEncoding.DecodeString(s)
	return string(b), err
}

// MostCommonChar 获取字符切片中出现最多的字符
func MostCommonChar(s []string) string {
	if len(s) == 0 {
		return ""
	}

	m := make(map[string]int)
	for _, v := range s {
		m[v]++
	}

	max := 0
	var maxChar string
	for k, v := range m {
		if v > max {
			max = v
			maxChar = k
		}
	}
	return maxChar
}

func TimeNowStr() string {
	return time.Now().Format("2006-01-02 15:04:05")
}

func TimeFormat(t time.Time) string {
	return t.Format("2006-01-02 15:04:05")
}

// Random 生成指定范围的随机数
func Random(min, max int) int {
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(max-min) + min
}
